﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;

namespace SVNManagementAddIn
{
    class PermissionHelper
    {
        #region 设置仓库权限

        /// <summary>
        /// 权限列表
        /// </summary>
        public enum AccessLevel : uint
        {
            NoAccess = 0,
            ReadOnly = 1,
            ReadWrite = 2
        }

        /// <summary>
        /// 设置仓库条目权限(添加成员)
        /// </summary>
        /// <param name="repository">仓库名称</param>
        /// <param name="path">仓库条目路径</param>
        /// <param name="name">实体名称</param>
        /// <param name="permission">访问权限</param>
        /// <returns></returns>
        public static bool SetRepositoryEntryPermission(string repository, string path, string name, string permission)
        {
            try
            {
                string[] names = name.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries);

                // 原有的权限
                IDictionary<string, AccessLevel> permissions = GetPermissions(repository, path);
                foreach (string s in names)
                {
                    if (permissions.ContainsKey(s))
                    {
                        // 先删除原有的权限
                        // 目的是支持权限更新
                        permissions.Remove(s);
                    }

                    if (permission.Equals("NoAccess"))
                    {
                        permissions.Add(s, AccessLevel.NoAccess);
                    }
                    else if (permission.Equals("ReadOnly"))
                    {
                        permissions.Add(s, AccessLevel.ReadOnly);
                    }
                    else if (permission.Equals("ReadWrite"))
                    {
                        permissions.Add(s, AccessLevel.ReadWrite);
                    }
                    else
                    {
                        permissions.Add(s, AccessLevel.ReadOnly);
                    }
                }

                SetPermissions(repository, path, permissions);
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        /// <summary>
        /// 设置仓库条目权限(删除成员)
        /// </summary>
        /// <param name="repository">仓库名称</param>
        /// <param name="path">仓库条目路径</param>
        /// <param name="name">实体名称</param>
        /// <returns></returns>
        public static bool SetRepositoryEntryPermission(string repository, string path, string name)
        {
            try
            {
                string[] names = name.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries);

                // 原有的权限
                IDictionary<string, AccessLevel> permissions = GetPermissions(repository, path);
                foreach (string s in names)
                {
                    if (permissions.ContainsKey(s))
                    {
                        // 删除原有的权限
                        permissions.Remove(s);
                    }
                }

                SetPermissions(repository, path, permissions);
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        /// <summary>
        /// 读取权限实体
        /// </summary>
        /// <param name="name">用户/组名称</param>
        /// <param name="accessLevel">访问权限</param>
        /// <returns></returns>
        private static ManagementObject GetPermissionObject(string name, AccessLevel accessLevel)
        {
            var entryClass = new ManagementClass(VisualSVN.ROOT,
                                                 VisualSVN._PermissionEntry, null);
            ManagementObject entry = entryClass.CreateInstance();
            ManagementClass accountClass;
            if (entry != null)
            {
                try
                { // 先根据组进行权限设置
                    List<ManagementBaseObject> list = GroupHelper.GetGroupMembersObject(name);
                    accountClass = new ManagementClass(VisualSVN.ROOT,
                                                               VisualSVN._Group, null);
                }
                catch (Exception ex)
                { // 组不存在，就找用户
                    accountClass = new ManagementClass(VisualSVN.ROOT,
                                                               VisualSVN._User, null);
                }
                ManagementObject account = accountClass.CreateInstance();
                if (account != null) account["Name"] = name;
                entry["Account"] = account;
                entry["AccessLevel"] = accessLevel;
            }
            return entry;
        }

        /// <summary>
        /// 设置仓库权限
        /// </summary>
        /// <param name="repositoryName">仓库名称</param>
        /// <param name="path">仓库条目路径</param>
        /// <param name="permissions">权限</param>
        private static void SetPermissions(string repositoryName, string path,
                                           IEnumerable<KeyValuePair<string, AccessLevel>> permissions)
        {
            ManagementObject repository = RepositoryHelper.GetRepositoryObject(repositoryName);
            ManagementBaseObject @params = repository.GetMethodParameters("SetSecurity");
            @params["Path"] = path;
            IEnumerable<ManagementObject> permissionObjects =
                permissions.Select(p => GetPermissionObject(p.Key, p.Value));
            ManagementObject[] objs = permissionObjects.ToArray();
            @params["Permissions"] = objs;
            repository.InvokeMethod("SetSecurity", @params, null);
        }

        /// <summary>
        /// 读取仓库权限
        /// </summary>
        /// <param name="repositoryName">仓库名称</param>
        /// <param name="path">仓库条目路径</param>
        /// <returns></returns>
        public static IDictionary<string, AccessLevel> GetPermissions(string repositoryName, string path)
        {
            ManagementObject repository = RepositoryHelper.GetRepositoryObject(repositoryName);
            ManagementBaseObject inParameters = repository.GetMethodParameters("GetSecurity");
            inParameters["Path"] = path;
            ManagementBaseObject outParameters = repository.InvokeMethod("GetSecurity", inParameters, null);

            var permissions = new Dictionary<string, AccessLevel>();

            if (outParameters != null)
                foreach (ManagementBaseObject p in (ManagementBaseObject[])outParameters["Permissions"])
                {
                    var account = (ManagementBaseObject)p["Account"];
                    var name = (string)account["Name"];
                    var accessLevel = (AccessLevel)p["AccessLevel"];

                    permissions[name] = accessLevel;
                }

            return permissions;
        }

        #endregion
    }
}
